﻿<%@ Page Culture="auto" UICulture="auto" Title="MForm navigation" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
    CodeBehind="Navigation.aspx.cs" Inherits="BM.Tools.WebControls.MForm.Example.Core.Navigation" %>

<%@ Register TagPrefix="mftitle" Namespace="BM.Tools.WebControls.MForm.Controls.Titles"
    Assembly="BM.Tools.WebControls.MForm" %>
<asp:Content ID="Content1" ContentPlaceHolderID="Description" runat="server">
    <div class="Section">
        <mftitle:TitleControl runat="server" Text="Testing the MForm navigation with the Navigation Toolbox" />
        <p>
            The MForm Toolbox that is placed on pages with MForm available has a special form called "Navigation Toolbox".
        </p>
        <p>
            The navigation toolbox allows providing a xpath expression and an action that should be performed on the found controls. 
            This is an easy way to learn MForm XPath subset.
        </p>
        <p>
            You will notice that the Navigation toolbox is also a MForm control. To see how it is implemented, see <span class="Important">~/Toolbox/MFormToolbox.ascx</span> user control.
        </p>
        <p>
            In order to enable the Navigation toolbox, the checkbox below must be enabled.
        </p>
        <div id="CheckBoxDiv" runat="server" style="margin: 0.6em; padding: 0.6em" >            
            <asp:CheckBox ID="ToolboxNavigationCheckBox" AutoPostBack="true" runat="server" OnCheckedChanged="ToggleToolboxNavigation" />
        </div>
        
    </div>    
    <div class="Section">
        <mftitle:TitleControl runat="server" Text="Navigating through MForm controls" />
        <p>
            Because MForm controls can be repeatedly generated using the <code>MinOccurs</code>
            and <code>MaxOccurs</code> properties, it is hard to relate to the inner MForm controls
            programmatically using only their IDs.
        </p>
        <p>
            To resolve this problem, a language for navigating through the controls has been
            prepared. This language is a subset of the <span class="Important">XML Path Language
                (XPath)</span>, taking advantage of the fact that MForm controls correspond
            to XML nodes.
        </p>
        <dl class="Example">
            <dt>Example 1</dt>
            <dd>
                <p>
                    Using this language, it is very easy to find for example all MForm controls, whose
                    local name equals "SomeControl".
                </p>
                <p>
                    The path would look like this: <code>//*:SomeControl</code>
                </p>
            </dd>
        </dl>
        <div class="Section">
            <mftitle:TitleControl runat="server" Text="The location path" />
            <p>
                The MForm XPath abbreviated syntax uses the <span class="Important">location path</span>
                construct. A location path may consist of one or more location steps.
            </p>
            <p>
                The navigation starts from one MForm control (usually a root, but can be started
                from any MForm control), this control is queried with the first location step from
                the location path resulting in an enumeration of MForm controls. All of the MForm
                controls in this enumeration are then queried with the next location step and so
                on until the last location step, which returns the output result of the whole location
                path.
            </p>
            <dl class="Example">
                <dt>Example 2</dt>
                <dd>
                    <p>
                        Assume that we start the navigation from an MForm control that has a child MForm
                        control called "Parent". This control has a child MForm control called "ItsChild",
                        and subsequently this control has a child MForm control called "TheGrandChild".
                    </p>
                    <p>
                        The path that directs to the last control would look like this: <code>Parent/ItsChild/TheGrandChild</code>
                    </p>
                </dd>
            </dl>
        </div>
        <div class="Section">
            <mftitle:TitleControl runat="server" Text="The single location step" />
            <p>
                A single location step has three parts:
            </p>
            <ul>
                <li>an axis, which specifies the tree relationship between the nodes selected by the
                    location step and the context node,</li>
                <li>a node test, which specifies the node type and expanded-name of the nodes selected
                    by the location step, and</li>
                <li>zero or more predicates, which use arbitrary expressions to further refine the set
                    of nodes selected by the location step.</li>
            </ul>
            <div class="Section">
                <mftitle:TitleControl runat="server" Text="The axes" />
                <p>
                    The MForm XPath abbreviated syntax allows 4 axes:
                </p>
                <ul>
                    <li>the child axis - <code>/</code></li>
                    <li>the descendant or self axis - <code>//</code></li>
                    <li>the self axis - <code>.</code></li>
                    <li>the parent axis - <code>..</code></li>
                </ul>
                <p>
                    In case of child axis and descendant or self axis, using the node test is required.
                    <br />
                    In case of the other two axes (the self axis and the parent axis), using the node
                    test is prohibited.
                </p>
                <dl class="Example">
                    <dt>Example 3</dt>
                    <dd>
                        <p>
                            When looking for all MForm controls, that have a "SomeControl" as child, you can
                            use this path:
                        </p>
                        <p>
                            <code>//SomeControl/..</code>
                        </p>
                    </dd>
                </dl>
                <dl class="Example">
                    <dt>Example 4</dt>
                    <dd>
                        <p>
                            Assume that we are in a MForm control that has a child named "Owner".
                        </p>
                        <p>
                            The path <code>Owner//.</code> will return the "Owner" control, its children, the
                            children of its children and so on.
                        </p>
                    </dd>
                </dl>
            </div>
            <div class="Section">
                <mftitle:TitleControl runat="server" Text="The node test" />
                <p>
                    The node test checks the name and type of the control.
                    <br />
                    The MForm XPath abbreviated syntax allows the following node tests:
                </p>
                <ul>
                    <li>the element node test - <code>ElementName</code> or <code>prefix:ElementName</code></li>
                    <li>the attribute node test - <code>@AttributeName</code></li>
                    <li>the all nodes test - <code>*</code></li>
                    <li>the all nodes in namespace test - <code>prefix:*</code></li>
                    <li>the all nodes with local name test - <code>*:LocalName</code></li>
                    <li>the all attributes test - <code>@*</code></li>
                </ul>
                <div class="Remark">
                    <p>
                        In real XPath attributes are not treated as children. So a <code>*</code> node test
                        does not return attributes On the contrary, MForm controls are treated as children
                        no matter if they represent elements or attributes, so the <code>*</code> will return
                        both the controls representing elements and attributes.
                    </p>
                    <p>
                        Also the <code>*:LocalName</code> test will test both attribute and element MForm
                        controls.
                    </p>
                </div>
                <dl class="Example">
                    <dt>Example 5</dt>
                    <dd>
                        <p>
                            When looking for all MForm controls representing attributes, whose parent's local
                            name is "AttributeOwner", use the following xpath: use this path:
                        </p>
                        <p>
                            <code>//*:AttributeOwner/@*</code>
                        </p>
                    </dd>
                </dl>
                <div class="Remark">
                    <p>
                        Another difference between real XPath and its MForm implementation is that XML works
                        on real nodes, whereas MForm works on controls that may, but don't have to build
                        a part of ouput XML.
                    </p>
                    <p>
                        Let's consider the MForm <code>Choice</code> control. The MForm output XML will
                        not use the name of the control anyhow, because only the selected item of the choice
                        control becomes part of the XML (so the standard XPath does not give a way to ask
                        about the choice control). But because there must be a way to locate the choice
                        control in the MForm tree, the choice control is treated by the query engine in
                        the same manner as it treats a control that represents an XML element.
                    </p>
                </div>
                <dl class="Example">
                    <dt>Example 6</dt>
                    <dd>
                        <p>
                            Assuming that we have a Choice MForm control named "Choice" located somewhere in
                            the tree and we want to find all its children (all the actual choices).
                        </p>
                        <p>
                            The proper XPath would be: <code>//Choice/*</code>
                        </p>
                    </dd>
                </dl>
            </div>
            <div class="Section">
                <mftitle:TitleControl runat="server" Text="The predicates" />
                <p>
                    The predicates in XPath are noted in square brackets - <code>[ ]</code>.
                </p>
                <p>
                    The implementation of predicates in MForm XPath is currently rudimentary. The only
                    predicate that MForm supports is the index predicate
                </p>
                <p>
                    If some MForm control has several instances under one parent, they can be disguised
                    using the index predicate. The index of the first control is <span class="Important">
                        1</span>.
                </p>
                <dl class="Example">
                    <dt>Example 7</dt>
                    <dd>
                        <p>
                            To find the first instance of the "Child" MForm control, use the following xpath:
                        </p>
                        <p>
                            <code>Child[1]</code>
                        </p>
                    </dd>
                </dl>
            </div>
        </div>
        <div class="Section">
            <mftitle:TitleControl runat="server" Text="The compound location step" />
            <p>
                MForm XPath implementation provides a possibility to use unions in location steps.
                The union is noted as a <code>|</code> between single location steps. All location
                steps constituting the union should be inside round brackets:
                <br />
                <code>(SingleLocationStep | OtherSingleLocationStep | EvenDifferentLocationStep)</code>
            </p>
            <p>
                The unions may be used only between location steps, not between parts of location
                paths.
            </p>
            <dl class="Example">
                <dt>Example 8</dt>
                <dd>
                    <p>
                        To find all attribute controls and the "AlsoMe" element control of the "Parent"
                        control, located under the control that we run the path, use the following xpath:
                    </p>
                    <p>
                        <code>Parent/(@* | AlsoMe)</code>
                    </p>
                </dd>
                <dt>Example 9</dt>
                <dd>
                    <p>
                        To find all controls whose parents are called "Mommy" or "Daddy", use the following
                        xpath:
                    </p>
                    <p>
                        <code>//(Mommy | Daddy)/*</code>
                    </p>
                </dd>
            </dl>
        </div>
    </div>
    <div class="Section">
        <mftitle:TitleControl runat="server" Text="Using MForm XPath navigation" />
        <p>
            MForm Xpath navigation should be simple and intuitive for all the developers that
            already know XPath. Besides few exceptions (described in the text above) the Xpath
            query run on the controls would also work as the XPath query run on the MForm output
            XML.
        </p>
        <p>
            The reason for creating the MForm XPath navigation language is actually creating
            such a simple an intuitive tool for querying MForm controls, not implementing the
            whole XPath functionality. Probably the MForm Xpath subset will be broadened a bit
            but only for consistency reasons (i.e. the descendant-or-self axis is implemented
            but the ancestor-or self axis is not).
        </p>
        <div class="Section">
            <mftitle:TitleControl runat="server" Text="MForm XPath and LINQ" />
            <p>
                It is worth mentioning that an output of the MForm XPath <code>Select</code> extension
                method is an <code>IEnumerable&lt;OffspringItem&gt;</code> controls, which further
                can be refined using the <code>LINQ</code> query (this is the most important reason
                why predicates are barely implemented in MForm, they can simply be done with LINQ).
            </p>
            <dl class="Example">
                <dt>Example 8</dt>
                <dd>
                    <p>Assume that we have a "sampleRoot" MForm Root control and we want to find all the item
                    controls with a value equal "true" and are the children of the "Flags" MForm control.<br />
                    This code will not work:</p>                    
                   
                        <code>sampleRoot.Select("//Flags/*[. = 'true']")</code>
                    
                    <p>because value predicate is not implemented with MForm XPath. However, the same thing can be implemented like this:</p>
                    
                        <code>sampleRoot.Select("//Flags/*").Leafs().Where(leafItem => leafItem.Value == "true")</code>
                    
                    <br />
                        (<code>Leafs()</code> is an extension method that does exactly the same as <code>OfType&lt;LeafItem&gt;()</code>)
                    
                    <p>
                        Of course the second query is longer, but on the other hand all steps are easier
                        to follow (first take only leaf items, because only them can have values, then check
                        the values) and what is more important, we get the actual control and can check
                        all of its properties (also having intellisense checking, etc.).
                    </p>
                </dd>
                <dt>Example 9</dt>
                <dd>
                    <p><code>LINQ</code> and MForm XPath can be combined in a manner where there is more
                    than one XPath query.</p>
                    <p>
                    Let's assume that we have a "clientsRoot" MForm Root control for providing many clients data. This
                    control may have the following tree structure:</p>
                    <ul>
                        <li>Clients
                            <ul>
                                <li>Client (1 to many)
                                    <ul>
                                        <li>FirstName </li>
                                        <li>Surname </li>
                                        <li>Adresses
                                            <ul>
                                                <li>Address (1 to many)
                                                    <ul>
                                                        <li>Street</li>
                                                        <li>City</li>
                                                    </ul>
                                                </li>
                                            </ul>
                                        </li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                    </ul>
                    <p>Now we want to find all the "Client" controls, that represent Mr. Jones, whose all
                    addresses are in the city of Jonestown.</p>
<pre>
<code>
clientsRoot.Select("//Client").Where(
    client => 
        client.Select("Surname").Leafs().Where(surname => surname.Value == "Jones")
        &&
        client.Select("Addresses/Address/City").Leafs().All(city => city.Value == "Jonestown")
);
</code>
</pre>
                </dd>
            </dl>
        </div>
    </div>
</asp:Content>
